package models.re;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.persistence.Query;

import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.query.dsl.QueryBuilder;

import play.db.jpa.JPA;
import scala.concurrent.duration.Duration;
import scala.concurrent.duration.FiniteDuration;
import models.aaa.Asset;
import models.aaa.Asset.Visibility;
import models.re.aaa.AAAAlgorithm;
import models.re.realData.AssetRank;
import models.re.realData.RealData;

import akka.actor.UntypedActor;
import akka.dispatch.BoundedMailbox;
import akka.dispatch.Dispatchers;
import akka.dispatch.MailboxType;
import akka.dispatch.MessageDispatcher;


public class Re {	
	
	public static class Launcher extends UntypedActor {
		
		public static volatile Boolean busy = false;

		public Boolean getBusy() {
			return busy;
		}

		@Override
		public void onReceive(Object message) throws Exception {
			// TODO Auto-generated method stub
			if(message instanceof Start) {
				busy = true;
				Start start = (Start) message;
				computeParallelAAA(start.getThreads());
				busy = false;
			}
			else {
				unhandled(message);
			}
			
		}
		
	}
	
	public static final class Start {
		
		private final int threads;
		
		public int getThreads() {
			return threads;
		}

		public Start(final int threads) {
			this.threads=threads;
		}		
	
	}

	public static void computeParallelAAA(int threads) {
		new RealData().computeAllSimilarities(threads);
		AAAAlgorithm.parallelCompute(threads);
	}
	
	@SuppressWarnings("unchecked")
	public static List<Asset> getRecommendation(AAAContext context,int limit) {
		/*
		FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search
                .getFullTextEntityManager(JPA.em());
		QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(AssetRank.class)
                .get();
		org.apache.lucene.search.Query beValid = qb.keyword().onFields("target.isValid").matching(true).createQuery();
		org.apache.lucene.search.Query beAccessible = null;
        if (context.getUser() != null) {
            org.apache.lucene.search.Query bePublic = qb.keyword().onFields("target.visibility").matching(Visibility.PUBLIC).createQuery();
            org.apache.lucene.search.Query beMine = qb.keyword().onFields("target.links").matching(context.getUser()).createQuery();

            org.apache.lucene.search.Query bePublicGroup = qb.keyword().onFields("target.group.visibility").matching(Visibility.PUBLIC)
                    .createQuery();
            org.apache.lucene.search.Query belongToGroup = qb.keyword().onFields("target.group.links").matching(context.getUser()).createQuery();

            beAccessible = qb.bool().should(bePublic).should(beMine).should(bePublicGroup)
                    .should(belongToGroup).createQuery();
        } else {
            org.apache.lucene.search.Query bePublic = qb.keyword().onFields("target.visibility").matching(Visibility.PUBLIC).createQuery();
            org.apache.lucene.search.Query bePublicGroup = qb.keyword().onFields("target.group.visibility").matching(Visibility.PUBLIC)
                    .createQuery();
            beAccessible = qb.bool().should(bePublic).should(bePublicGroup).createQuery();
        }
        org.apache.lucene.search.Query match = qb.keyword().onFields("source.id").matching(context.getItem().getId()).createQuery();
		
        //org.apache.lucene.search.Query query = qb.bool().must(beValid).must(beAccessible).must(match).createQuery();
        org.apache.lucene.search.Query query = qb.bool().must(beValid).must(match).createQuery();
        FullTextQuery result = fullTextEntityManager.createFullTextQuery(query, Asset.class);
        return result.setMaxResults(10).getResultList();
        */
        String sql = "SELECT * FROM AssetRank WHERE source_id = ? ORDER BY value DESC LIMIT ?";
        Query query = JPA.em().createNativeQuery(sql);
        query.setParameter(1, context.getItemId());
        query.setParameter(2, limit);
        @SuppressWarnings("unchecked")
        ArrayList<Object[]> tmp = new ArrayList<Object[]>(query.getResultList());
        ArrayList<IRank> res = new ArrayList<IRank>();
        ArrayList<Asset> result = new ArrayList<Asset>();
        for(Object[] s: tmp) res.add(AssetRank.findById(((BigInteger)s[0]).longValue()));
        for(IRank rank: res) result.add(Asset.find.byId(rank.getTarget().getId()));
		return result;
	}
	
	public static List<Asset> getRecommendation2(AAAContext context, String actor, int limit) {
//		String sql = "SELECT ar.* FROM AssetRank ar, Asset a WHERE source_id = ? AND ar.target_id = a.id AND a.type = ? ORDER BY value DESC LIMIT ?";
		String sql = "SELECT ar.* FROM AssetRank ar, Asset a WHERE source_id = ? AND ar.target_id = a.id AND a.type = ? ORDER BY value DESC";
        Query query = JPA.em().createNativeQuery(sql);
        query.setParameter(1, context.getItemId());
        query.setParameter(2, context.getType());
//        query.setParameter(3, limit);
        @SuppressWarnings("unchecked")
        ArrayList<Object[]> tmp = new ArrayList<Object[]>(query.getResultList());
        ArrayList<IRank> res = new ArrayList<IRank>();
        ArrayList<Asset> result = new ArrayList<Asset>();
        for(Object[] s: tmp) res.add(AssetRank.findById(((BigInteger)s[0]).longValue()));
        for(IRank rank: res){
            Asset asset = Asset.find.byId(rank.getTarget().getId());
            Asset user = Asset.find.byUid(actor);
//            if (asset.access().isAllowed(user)) {//TODO gestion des droits
//                result.add(asset);
//            }
            result.add(asset);
        }
        
        if (result.size() > limit) {
            return result.subList(0, limit);
        } else {
    		return result;
    	}
	}
	
	public static ArrayList<Asset> getDummyRecommendation(AAAContext context,int limit) {
	    String where = "";
	    String type = context.getType();
	    if (type != null) {
	        where = " WHERE type = '" + type + "' ";
	    }
		String sql = "SELECT e FROM Asset e " + where + " ORDER BY RAND()";
        Query query = JPA.em().createQuery(sql);
        query.setMaxResults(limit);
        @SuppressWarnings("unchecked")
		ArrayList<Asset> tmp = new ArrayList<Asset>(query.getResultList());
		return tmp;
	}

}
